﻿using Devil;
using OfficeOpenXml;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using TableCore;

namespace TableTranslate
{
    internal class UpdateXmlTexts : ICommand
    {
        class OutputText
        {
            public int row;
            public string comment;
            public string text;
        }

        class InputText
        {
            public int id;
            public string content;
            public List<string> comments;
            public InputText(XmlElement node)
            {
                if (node == null || node.Name != "Text")
                    throw new Exception("Xml 节点错误");
                id = int.Parse(node.GetAttribute("id"));
                comments = new List<string>();
                var child = node.FirstChild;
                while (child != null)
                {
                    if (child.NodeType == XmlNodeType.Comment)
                    {
                        var txt = ((XmlComment)child).InnerText;
                        comments.Add(txt);
                    }
                    else if (child.NodeType == XmlNodeType.Element && child.Name == "Content")
                    {
                        content = ((XmlElement)child).InnerText;
                    }
                    child = child.NextSibling;
                }
            }

            public bool GetDifferentComments(OutputText output)
            {
                if (string.IsNullOrEmpty(output.comment))
                    return false;
                var cms = output.comment.Split('\n');
                for (int i = 0; i < cms.Length; i++)
                {
                    var cm = cms[i];
                    bool exist = false;
                    for (int k = 0; k < comments.Count; k++)
                    {
                        if (cm == comments[k])
                        {
                            exist = true;
                            break;
                        }
                    }
                    if (!exist)
                        return true;
                }
                return false;
            }
        }

        bool dirty;
        readonly object _lock = new object();
        ExcelPackage package;
        ExcelWorksheet sheet;
        HashSet<int> validateRows;
        int rows;
        int idCol = -1, txtCol = -1, commentCol = -1;
        List<OutputText> exportTexts;
        List<InputText> importTexts;

        public void Execute()
        {
            validateRows = new HashSet<int>();
            var xml = Program.ReadText("输入 XML: ");
            if (string.IsNullOrEmpty(xml) || !File.Exists(xml))
            {
                Console.WriteLine(string.Format("无效的 Xml 文件: {0}.", xml));
                return;
            }
            var loadTxt = ParallelUtils.Schedule(LoadTexts, xml, false);
            var excel = Program.ReadText("输出 Excel: ");
            if (string.IsNullOrEmpty(excel) || !File.Exists(excel))
            {
                Console.WriteLine(string.Format("无效的 Excel 文件: {0}", excel));
                loadTxt.Abort();
                return;
            }
            var cmds = ParallelUtils.Schedule(ExportTexts, excel, false, loadTxt);
            while (cmds.IsValid)
            {
            }

            //if (importTexts == null || importTexts.Count == 0)
            //{
            //    Console.WriteLine("没有文本内容");
            //    return;
            //}
            Console.WriteLine(string.Format("已导入文本: {0}", xml));
        }

        void LoadTexts(string xml)
        {
            importTexts = new List<InputText>();
            var file = new XmlDocument();
            file.Load(xml);
            var node = file.FirstChild;
            XmlNode root = null;
            while (node != null)
            {
                if (node.Name == "Translate-Assets")
                {
                    root = node;
                    break;
                }
                else
                {
                    node = node.NextSibling;
                }
            }
            if (root == null)
            {
                return;
            }
            var item = root.FirstChild;
            while (item != null)
            {
                if (item is XmlElement)
                    importTexts.Add(new InputText((XmlElement)item));
                item = item.NextSibling;
            }
        }

        IEnumerator ExportTexts(string excelFile)
        {
            InitTableInfo(excelFile);
            if (idCol == -1 || txtCol == -1)
                yield break;
            yield return ParallelUtils.ScheduleParallel<InputText>(UpdateItem, importTexts);
            FinishAndDispose();
        }

        void InitTableInfo(string excelFile)
        {
            exportTexts = new List<OutputText>();
            dirty = false;
            package = new ExcelPackage(new FileInfo(excelFile));
            sheet = package.Workbook.Worksheets[1];
            rows = sheet.Cells.Rows;
            commentCol = 1;
            idCol = -1;
            txtCol = -1;
            for (int i = 2; i < 8; i++)
            {
                var txt = sheet.Cells[1, i].Text;
                if (StringUtil.EqualIgnoreCase(txt, "id"))
                    idCol = i;
                else if (StringUtil.EqualIgnoreCase(txt, "text.cn") || StringUtil.EqualIgnoreCase(txt, "text"))
                    txtCol = i;
                if (idCol != -1 && txtCol != -1)
                    break;
            }
            if (idCol == -1 || idCol == -1)
            {
                Console.WriteLine("没有找到列（id, text.cn 或 text）");
                return;
            }
            var emptyLines = 0;
            for (int row = 4; row <= rows; row++)
            {
                var comment = sheet.Cells[row, commentCol].Text;
                var txt = sheet.Cells[row, txtCol].Text;
                if (string.IsNullOrEmpty(comment) && string.IsNullOrEmpty(txt))
                {
                    emptyLines++;
                    if (emptyLines > 3)
                        break;
                    else
                        continue;
                }
                OutputText output = new OutputText();
                output.row = row;
                output.comment = comment;
                output.text = txt;
                exportTexts.Add(output);
                rows = row;
            }
        }

        void UpdateItem(InputText info)
        {
            int num = 0;
            OutputText export = null;
            while (export == null)
            {
                OutputText output;
                var i = num++;
                lock (_lock)
                {
                    if (num >= exportTexts.Count)
                        break;
                    output = exportTexts[i];
                }
                if (output.row == -1)
                    break;
                if (output.text == info.content)
                {
                    export = output;
                    break;
                }
                else if (!string.IsNullOrEmpty(output.comment))
                {
                    for (int k = 0; k < info.comments.Count; k++)
                    {
                        if (output.comment.Contains(info.comments[i]))
                        {
                            export = output;
                            break;
                        }
                    }
                }
            }
            var buf = StringUtil.GetBuilder();
            for (int i = 0; i < info.comments.Count; i++)
            {
                if (i > 0)
                    buf.Append(',');
                buf.Append(info.comments[i]);
            }
            var comment = StringUtil.ReturnRelease(buf);
            if (export != null)
            {
                dirty |= export.text != info.content || export.comment != comment;
                export.text = info.content;
                export.comment = comment;
            }
            else
            {
                dirty = true;
                var output = new OutputText();
                output.row = -1;
                output.text = info.content;
                output.comment = comment;
                lock (_lock)
                {
                    exportTexts.Add(output);
                }
            }
        }

        void FinishAndDispose()
        {
            lock (_lock)
            {
                if (package != null)
                {
                    if (dirty)
                    {
                        int row = 4;
                        for (int i = 0; i < exportTexts.Count; i++)
                        {
                            var export = exportTexts[i];
                            if (export.row != -1)
                                row = row > export.row ? row : export.row;
                            sheet.Cells[row, txtCol].Value = export.text;
                            sheet.Cells[row, idCol].Value = StringUtil.ToHash(export.text).ToString();
                            //sheet.Cells[row, commentCol].Value = export.comment;
                            row++;
                        }

                        package.Save();
                    }
                    package.Dispose();
                    package = null;
                    exportTexts.Clear();
                    importTexts.Clear();
                    dirty = false;
                }
            }
        }

        public override string ToString()
        {
            return "导入 XML 文本";
        }
    }
}
